
#pragma once

#include <entt/entt.hpp>
#include "ly/cell.hpp"
#include "ly/export.hpp"
#include "ly/layers.hpp"
#include "ly/pcell_header.hpp"
#include "ly/properties.hpp"

namespace ly {

class Library;
class Layout;
class PCellHeader;

class LY_API Layout : public Object {
 public:
  typedef std::shared_ptr<Layout> sptr;
  typedef std::shared_ptr<Layout> layout_sptr;
  typedef std::shared_ptr<Layout> layout_wptr;
  typedef std::shared_ptr<Library> library_sptr;
  typedef std::weak_ptr<Library> library_wptr;
  typedef std::shared_ptr<Manager> manager_sptr;
  typedef std::shared_ptr<Cell> cell_sptr;
  typedef std::shared_ptr<PCellHeader> pcell_header_sptr;

 public:
  Layout() {};
  Layout(library_wptr parent) : mp_library(parent) {};
  ~Layout() {};

  template <typename... Args>
  static layout_sptr create(Args&&... args) {
    return std::make_shared<Layout>(std::forward<Args>(args)...);
  }
  layout_sptr clone() const { return std::make_shared<Layout>(*this); }

  library_sptr library() { return mp_library.lock(); }

  void library(library_sptr library) { mp_library = library; }

  void dbu(double v) { m_dbu = v; };
  double dbu() { return m_dbu; };

  cell_id_type add_cell(const std::string& name);

  bool is_exist_cell(const std::string& name) { return m_name_by_id.find(name) != m_name_by_id.end(); };

  cell_sptr cell(const std::string& name) { return m_cells[m_name_by_id[name]]; };

  cell_sptr cell(cell_id_type id) { return m_cells[id]; };

  void rename_cell(cell_id_type id, const char* name);

  Properties& properties() { return m_properties; }
  properties_id_type prop_id() const { return m_prop_id; }
  void prop_id(properties_id_type id);

  Layers& layers() { return m_layers; }

  bool is_editable() const { return m_editable; }

  // const pcell_header_sptr pcell_header(pcell_id_type pcell_id) const;
  pcell_header_sptr pcell_header(pcell_id_type pcell_id);

 private:
  layout_sptr this_sptr() { return std::dynamic_pointer_cast<Layout>(shared_from_this()); }

 private:
  properties_id_type m_prop_id;

  Properties m_properties;
  Layers m_layers;

  library_wptr mp_library;

  std::vector<cell_sptr> m_cells;
  std::vector<std::string> m_cell_names;
  std::unordered_map<std::string, cell_id_type> m_name_by_id;

  // std::vector<PCell::s_ptr> m_pcells;

  std::vector<pcell_header_sptr> m_pcells;

  double m_dbu;
  bool m_editable;
};
}  // namespace ly
